﻿using SuperMap.Analyst.SpatialAnalyst;
using SuperMap.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace MDF
{
    /// <summary>
    /// 几何匹配
    /// </summary>
    class MatchSpace
    {
        /// <summary>
        /// 几何匹配初始化
        /// </summary>
        public MatchSpace()
        {
            //初始化统计进度
            DatasetsMatchResult.SpaceProgressCount = 0;
            DatasetsMatchResult.SpaceProgressValue = 0;
        }
        /// <summary>
        /// 几何匹配初始化
        /// </summary>
        /// <param name="IsStart">是否初始化进度</param>
        public MatchSpace(bool IsStart)
        {
            if (IsStart)
            {
                //初始化统计进度
                DatasetsMatchResult.SpaceProgressCount = 0;
                DatasetsMatchResult.SpaceProgressValue = 0;
            }
            
        }
        /// <summary>
        /// 点要素空间匹配
        /// </summary>
        /// <param name="point1">点记录集1</param>
        /// <param name="point2">点记录集2</param>
        /// <param name="DistanceTh">距离阈值，单位m</param>
        /// <param name="unit">数据集坐标单位</param>
        /// <returns>返回点空间匹配的结果列表，其单个元素形式为double[] { geoPoint1.ID, geoPoint2.ID, Sim }</returns>
        public List<double[]> MatchDataPoint1(Recordset point1, Recordset point2, double DistanceTh, Unit unit)
        {
            try
            {
                //记录匹配结果信息
                List<double[]> SimPoints = new List<double[]>();
                //遍历计算坐标并匹配smid值
                point1.MoveFirst();
                for (int i = 0; i < point1.RecordCount; i++)
                {
                    //获取点对像1
                    GeoPoint geoPoint1 = point1.GetGeometry() as GeoPoint;
                    point2.MoveFirst();
                    for (int j = 0; j < point2.RecordCount; j++)
                    {
                        //获取点对像2
                        GeoPoint geoPoint2 = point2.GetGeometry() as GeoPoint;
                        //距离计算
                        double d = GetDistance(geoPoint1.X, geoPoint1.Y, geoPoint2.X, geoPoint2.Y, unit);
                        if (d != -1 && d < DistanceTh)
                        {
                            //满足距离阈值，先记录信息，相似性则再选用归一化处理（离差标准化）
                            //归一化，min取0，max取阈值，得到下面的公式
                            double sim = 1 - d / DistanceTh;
                            //记录匹配结果信息
                            SimPoints.Add(new double[] { geoPoint1.ID, geoPoint2.ID, sim });
                        }
                        point2.MoveNext();
                        //释放局部资源
                        geoPoint2.Dispose();
                    }
                    point1.MoveNext();
                    //释放局部资源
                    geoPoint1.Dispose();
                }
                //返回匹配结果
                return SimPoints;
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 点要素空间匹配
        /// </summary>
        /// <param name="point1">点记录集1</param>
        /// <param name="point2">点记录集2</param>
        /// <param name="DistanceTh">距离阈值，单位m</param>
        /// <param name="unit">数据集坐标单位</param>
        /// <param name="Token">取消操作的对象</param>
        /// <returns>返回点空间匹配的结果列表，其单个元素形式为double[] { geoPoint1.ID, geoPoint2.ID, Sim }</returns>
        public List<double[]> MatchDataPoint1(Recordset point1, Recordset point2, double DistanceTh, Unit unit, CancellationToken Token)
        {
            try
            {
                //记录匹配结果信息
                List<double[]> SimPoints = new List<double[]>();
                //遍历计算坐标并匹配smid值
                point1.MoveFirst();
                for (int i = 0; i < point1.RecordCount; i++)
                {
                    //获取点对像1
                    GeoPoint geoPoint1 = point1.GetGeometry() as GeoPoint;
                    point2.MoveFirst();
                    for (int j = 0; j < point2.RecordCount; j++)
                    {
                        if (Token.IsCancellationRequested)
                        {
                            //释放局部资源
                            geoPoint1.Dispose();
                            return null;
                        }
                        else
                        {
                            //获取点对像2
                            GeoPoint geoPoint2 = point2.GetGeometry() as GeoPoint;
                            //距离计算
                            double d = GetDistance(geoPoint1.X, geoPoint1.Y, geoPoint2.X, geoPoint2.Y, unit);
                            if (d != -1 && d < DistanceTh)
                            {
                                //满足距离阈值，先记录信息，相似性则再选用归一化处理（离差标准化）
                                //归一化，min取0，max取阈值，得到下面的公式
                                double sim = 1 - d / DistanceTh;
                                //记录匹配结果信息
                                SimPoints.Add(new double[] { geoPoint1.ID, geoPoint2.ID, sim });
                            }
                            point2.MoveNext();
                            //释放局部资源
                            geoPoint2.Dispose();
                            //记录进度
                            DatasetsMatchResult.SpaceProgressCount++;
                            DatasetsMatchResult.SpaceProgressValue = DatasetsMatchResult.SpaceProgressCount * 100 / DatasetsMatchResult.SetsRecordCountSum;
                        }
                    }
                    point1.MoveNext();
                    //释放局部资源
                    geoPoint1.Dispose();
                }
                //返回匹配结果
                return SimPoints;
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 点要素空间匹配(使用SuperMap类，性能更高)
        /// </summary>
        /// <param name="point1">记录集1</param>
        /// <param name="point2">记录集2</param>
        /// <param name="DistanceTh">距离阈值，单位m</param>
        private void MatchDataPoint2(Recordset point1, Recordset point2, double DistanceTh)
        {
            try
            {

                //ComputeRangeDistance方法计算阈值内所有要素的距离值
                ComputeDistanceResult[] computeDistanceResults = ProximityAnalyst.ComputeRangeDistance(point1, point2, 0, DistanceTh);
                foreach (ComputeDistanceResult computeDistanceResult in computeDistanceResults)
                {

                }

            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 线要素空间匹配
        /// </summary>
        /// <param name="line1">线记录集1</param>
        /// <param name="line2">线记录集2</param>
        /// <param name="DistanceTh">距离阈值，单位m</param>
        /// <param name="LengthTh">线要素长度误差，单位m</param>
        /// <param name="unit">数据集坐标单位</param>
        /// <returns>返回线空间匹配的结果列表，其单个元素形式为double[] { geoLine1.ID, geoLine2.ID, Sim }</returns>
        public List<double[]> MatchDataLine(Recordset line1, Recordset line2, double DistanceTh, double LengthTh, Unit unit)
        {
            try
            {
                //记录匹配信息
                List<double[]> SimLines = new List<double[]>();
                //遍历计算坐标并匹配smid值
                line1.MoveFirst();
                for (int i = 0; i < line1.RecordCount; i++)
                {
                    //获取线对像1
                    GeoLine geoLine1 = line1.GetGeometry() as GeoLine;
                    line2.MoveFirst();
                    for (int j = 0; j < line2.RecordCount; j++)
                    {
                        //获取线对像2
                        GeoLine geoLine2 = line2.GetGeometry() as GeoLine;
                        //坐标距离(阈值2m)
                        double distance = GetDistance(geoLine1.InnerPoint.X, geoLine1.InnerPoint.Y, geoLine2.InnerPoint.X, geoLine2.InnerPoint.Y, unit);
                        //总长度（阈值1m）
                        double length = Math.Abs(geoLine1.Length - geoLine2.Length);
                        //在距离阈值范围内的，才进行形状相似性的计算
                        if (distance <= DistanceTh && length <= LengthTh)
                        {
                            //计算距离相似性，和点距离计算一致（归一化）
                            double simD = 1 - distance / DistanceTh;
                            //计算形状相似性
                            double simS = MatchShapeLine(geoLine1, geoLine2);
                            //输出结果信息，相似度为simD*simS
                            SimLines.Add(new double[] { geoLine1.ID, geoLine2.ID, simD * simS });
                        }
                        line2.MoveNext();
                        //释放局部资源
                        geoLine2.Dispose();
                    }
                    line1.MoveNext();
                    //释放局部资源
                    geoLine1.Dispose();
                }
                //返回匹配结果
                return SimLines;
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 线要素空间匹配
        /// </summary>
        /// <param name="line1">线记录集1</param>
        /// <param name="line2">线记录集2</param>
        /// <param name="DistanceTh">距离阈值，单位m</param>
        /// <param name="LengthTh">线要素长度误差，单位m</param>
        /// <param name="unit">数据集坐标单位</param>
        /// <param name="Token">取消操作的对象</param>
        /// <returns>返回线空间匹配的结果列表，其单个元素形式为double[] { geoLine1.ID, geoLine2.ID, Sim }</returns>
        public List<double[]> MatchDataLine(Recordset line1, Recordset line2, double DistanceTh, double LengthTh, Unit unit, CancellationToken Token)
        {
            try
            {
                //记录匹配信息
                List<double[]> SimLines = new List<double[]>();
                //遍历计算坐标并匹配smid值
                line1.MoveFirst();
                for (int i = 0; i < line1.RecordCount; i++)
                {
                    //获取线对像1
                    GeoLine geoLine1 = line1.GetGeometry() as GeoLine;
                    line2.MoveFirst();
                    for (int j = 0; j < line2.RecordCount; j++)
                    {
                        if (Token.IsCancellationRequested)
                        {
                            //释放局部资源
                            geoLine1.Dispose();
                            return null;
                        }
                        else
                        {
                            //获取线对像2
                            GeoLine geoLine2 = line2.GetGeometry() as GeoLine;
                            //坐标距离(阈值2m)
                            double distance = GetDistance(geoLine1.InnerPoint.X, geoLine1.InnerPoint.Y, geoLine2.InnerPoint.X, geoLine2.InnerPoint.Y, unit);
                            //总长度（阈值1m）
                            double length = Math.Abs(geoLine1.Length - geoLine2.Length);
                            //在距离阈值范围内的，才进行形状相似性的计算
                            if (distance <= DistanceTh && length <= LengthTh)
                            {
                                //计算距离相似性，和点距离计算一致（归一化）
                                double simD = 1 - distance / DistanceTh;
                                //计算形状相似性
                                double simS = MatchShapeLine(geoLine1, geoLine2);
                                //输出结果信息，相似度为simD*simS
                                SimLines.Add(new double[] { geoLine1.ID, geoLine2.ID, simD * simS });
                            }
                            line2.MoveNext();
                            //释放局部资源
                            geoLine2.Dispose();
                            //记录进度
                            DatasetsMatchResult.SpaceProgressCount++;
                            DatasetsMatchResult.SpaceProgressValue = DatasetsMatchResult.SpaceProgressCount * 100 / DatasetsMatchResult.SetsRecordCountSum;

                        }
                    }
                    line1.MoveNext();
                    //释放局部资源
                    geoLine1.Dispose();
                }
                //返回匹配结果
                return SimLines;
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 计算相似性（考虑异向性）
        /// </summary>
        /// <param name="geoLine1">线对象1</param>
        /// <param name="geoLine2">线对象2</param>
        /// <returns>返回这两个线对像的相似度，[0,1]之间</returns>
        private double MatchShapeLine(GeoLine geoLine1, GeoLine geoLine2)
        {
            try
            {
                //获取子对象长度集
                double[] geoLine1S = GetLineChilds(geoLine1);
                double[] geoLine2S = GetLineChilds(geoLine2);
                if (geoLine1S.Length != geoLine2S.Length)
                {
                    //需要校正并计算相似性
                    double sim = CheckData(geoLine1S, geoLine2S, geoLine1, geoLine2);
                    //返回结果
                    return sim;
                }
                else
                {
                    //无需校正直接计算相似性
                    //获取首尾单段相似性
                    double firstSim = GetSim(geoLine1S[0], geoLine2S[0], geoLine1[0], geoLine2[0], true);
                    double endSim = GetSim(geoLine1S[0], geoLine2S[geoLine2S.Length - 1], geoLine1[0], geoLine2[geoLine2.PartCount - 1], false);
                    //正向，else反向
                    double sim = 0;
                    if (firstSim >= endSim)
                    {
                        //正向计算相似性
                        sim = GetSim(geoLine1S, geoLine2S, geoLine1, geoLine2, true);
                    }
                    else
                    {
                        //反向计算
                        sim = GetSim(geoLine1S, geoLine2S, geoLine1, geoLine2, false);
                    }
                    //返回结果
                    return sim;
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 获取子对象长度百分比集
        /// </summary>
        /// <param name="geoLine">需要获取子对象长度百分比集的线对象</param>
        /// <returns>返回该线对像的子对象长度百分比集数组</returns>
        private double[] GetLineChilds(GeoLine geoLine)
        {
            try
            {
                //记录子对象的长度百分比
                List<double> lengths = new List<double>();
                //获取子对象长度集
                for (int i = 0; i < geoLine.PartCount; i++)
                {
                    double length = new GeoLine(geoLine[i]).Length;

                    lengths.Add(length / geoLine.Length);
                }
                //返回结果
                return lengths.ToArray();
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 计算整体相似度
        /// </summary>
        /// <param name="geoLine1S">线对象1的子对象长度百分比集</param>
        /// <param name="geoLine2S">线对象2的子对象长度百分比集</param>
        /// <param name="geoLine1">线对象1</param>
        /// <param name="geoLine2">线对象2</param>
        /// <param name="firstORend">是否反向计算，true为正向，false反向</param>
        /// <returns>返回两线对象之间的整体相似度，[0,1]之间</returns>
        private double GetSim(double[] geoLine1S, double[] geoLine2S, GeoLine geoLine1, GeoLine geoLine2, bool firstORend)
        {
            try
            {
                double Sim = 0;
                //else反向
                if (firstORend)
                {
                    //正向计算每一段相似度的和
                    double Sims = 0;
                    for (int i = 0; i < geoLine1S.Length; i++)
                    {
                        double X1 = geoLine1[i][1].X - geoLine1[i][0].X;
                        double Y1 = geoLine1[i][1].Y - geoLine1[i][0].Y;
                        double X2 = geoLine2[i][1].X - geoLine2[i][0].X;
                        double Y2 = geoLine2[i][1].Y - geoLine2[i][0].Y;
                        //计算向量的Cos值（夹角）并乘以长度百分比，作为向量的相似度
                        double A = (X1 * X2 + Y1 * Y2) / (Math.Sqrt(X1 * X1 + Y1 * Y1) * Math.Sqrt(X2 * X2 + Y2 * Y2));
                        double L = 1 - Math.Abs(geoLine1S[i] - geoLine2S[i]) / geoLine1S[i];
                        //判读计算的是否有结果（计算中有0的话，计算就是没结果的，更具实际分析做以下判断）
                        if (double.IsNaN(A))
                        {
                            //如果都为0，则相似度为一，否则为零
                            if ( X1 + Y1 == X2 + Y2 )
                            {
                                A = 1;
                            }
                            else
                            {
                                A = 0;
                            }
                        }
                        //上面判断后，L可以不再重复判断
                        if (double.IsNaN(L))
                        {
                            L = 1;
                        }
                        //求出单段相似度，在累加
                        Sims += A * L;
                    }
                    //计算整体的相似度，也就是累加乘以 n分之一
                    Sim = Sims / geoLine1S.Length;
                }
                else
                {
                    //反向计算每一段相似度的和
                    double Sims = 0;
                    for (int i = 0; i < geoLine1S.Length; i++)
                    {
                        int j = geoLine1S.Length - i - 1;
                        double X1 = geoLine1[i][1].X - geoLine1[i][0].X;
                        double Y1 = geoLine1[i][1].Y - geoLine1[i][0].Y;
                        double X2 = geoLine2[j][1].X - geoLine2[j][0].X;
                        double Y2 = geoLine2[j][1].Y - geoLine2[j][0].Y;
                        //计算向量的Cos值（夹角）并乘以长度百分比，作为向量的相似度
                        double A = (X1 * X2 + Y1 * Y2) / (Math.Sqrt(X1 * X1 + Y1 * Y1) * Math.Sqrt(X2 * X2 + Y2 * Y2));
                        double L = 1 - Math.Abs(geoLine1S[i] - geoLine2S[j]) / geoLine1S[i];
                        //判读计算的是否有结果（计算中有0的话，计算就是没结果的，根据实际分析做以下判断）
                        if (double.IsNaN(A))
                        {
                            //如果都为0，则相似度为一，否则为零
                            if (X1 + Y1 == X2 + Y2)
                            {
                                A = 1;
                            }
                            else
                            {
                                A = 0;
                            }
                        }
                        //上面判断后，L可以不再重复判断
                        if (double.IsNaN(L))
                        {
                            L = 1;
                        }
                        //求出单段相似度，在累加
                        Sims += A * L;
                    }
                    //计算整体的相似度，也就是累加乘以 n分之一
                    Sim = Sims / geoLine1S.Length;
                }
                //返回结果
                return Sim;
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 单段相似度
        /// </summary>
        /// <param name="geoLine1s">线对象1的一个子对象长度百分比</param>
        /// <param name="geoLine2s">线对象2的一个子对象长度百分比</param>
        /// <param name="geoLine1">线对象1</param>
        /// <param name="geoLine2">线对象2</param>
        /// <param name="fristORend">是否反向计算，true为正向，false反向</param>
        /// <returns>返回两线对象之间的单段相似度，[0,1]之间</returns>
        private double GetSim(double geoLine1s, double geoLine2s, Point2Ds geoLine1, Point2Ds geoLine2, bool fristORend)
        {
            try
            {
                double X1 = geoLine1[1].X - geoLine1[0].X;
                double Y1 = geoLine1[1].Y - geoLine1[0].Y;
                double X2 = geoLine2[1].X - geoLine2[0].X;
                double Y2 = geoLine2[1].Y - geoLine2[0].Y;
                if (!fristORend)
                {
                    //尾端取相反向量坐标
                    X2 = geoLine2[0].X - geoLine2[1].X;
                    Y2 = geoLine2[0].Y - geoLine2[1].Y;
                }
                //计算向量的Cos值（夹角）并乘以长度百分比，作为向量的相似度
                double A = (X1 * X2 + Y1 * Y2) / (Math.Sqrt(X1 * X1 + Y1 * Y1) * Math.Sqrt(X2 * X2 + Y2 * Y2));
                double L = 1 - Math.Abs(geoLine1s - geoLine2s) / geoLine1s;
                //判读计算的是否有结果（计算中有0的话，计算就是没结果的，更具实际分析做以下判断）
                if (double.IsNaN(A))
                {
                    //如果都为0，则相似度为一，否则为零
                    if (X1 + Y1 == X2 + Y2)
                    {
                        A = 1;
                    }
                    else
                    {
                        A = 0;
                    }
                }
                //上面判断后，L可以不再重复判断
                if (double.IsNaN(L))
                {
                    L = 1;
                }
                //不用释放资源
                //返回sim结果
                return A * L;

            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 校正节点数据，并进行相似性计算
        /// </summary>
        /// <param name="geoLine1S">线对象1的子对象长度百分比集</param>
        /// <param name="geoLine2S">线对象2的子对象长度百分比集</param>
        /// <param name="geoLine1">线对象1</param>
        /// <param name="geoLine2">线对象2</param>
        /// <returns>返回校正后，这两个线对像的相似度，[0,1]之间</returns>
        private double CheckData(double[] geoLine1S, double[] geoLine2S, GeoLine geoLine1, GeoLine geoLine2)
        {
            try
            {
                //对数据节点校正,完成后自动进行相似性计算
                //获取百分比数列
                List<double> line1S = geoLine1S.ToList();
                List<double> line2S = geoLine2S.ToList();
                //获取节点数列
                Point2Ds point2Ds1 = GetNewPoint2Ds(geoLine1);
                Point2Ds point2Ds2 = GetNewPoint2Ds(geoLine2);
                int count = Math.Max(line1S.Count, line2S.Count);
                for (int i = 0; i < count; i++)
                {
                    if ((decimal)line1S[i] - (decimal)line2S[i] > (decimal)1.0)
                    {
                        //对百分比进行修正(警告：存在问题)
                        decimal s = (decimal)line1S[i] - (decimal)line2S[i];
                        line1S.RemoveAt(i);
                        line1S.Insert(i, line2S[i]);
                        line1S.Insert(i + 1, (double)s);
                        //再对象中添加节点
                        double x = (point2Ds1[i].X + point2Ds1[i + 1].X) * line2S[i];
                        double y = (point2Ds1[i].Y + point2Ds1[i + 1].Y) * line2S[i];
                        point2Ds1.Insert(i, new Point2D(x, y));

                    }
                    else if ((decimal)line2S[i] - (decimal)line1S[i] > (decimal)1.0)
                    {
                        decimal s = (decimal)line2S[i] - (decimal)line1S[i];
                        line2S.RemoveAt(i);
                        line2S.Insert(i, line1S[i]);
                        line2S.Insert(i + 1, (double)s);
                        //再对象中添加节点
                        double x = (point2Ds2[i].X + point2Ds2[i + 1].X) * line1S[i];
                        double y = (point2Ds2[i].Y + point2Ds2[i + 1].Y) * line1S[i];
                        point2Ds2.Insert(i, new Point2D(x, y));
                    }
                    count = Math.Max(line1S.Count, line2S.Count);
                }
                //更新修正后的数据
                geoLine1S = line1S.ToArray();
                geoLine2S = line2S.ToArray();
                geoLine1 = new GeoLine(point2Ds1);
                geoLine2 = new GeoLine(point2Ds2);

                //获取首尾单段相似性
                double firstSim = GetSim(geoLine1S[0], geoLine2S[0], geoLine1[0], geoLine2[0], true);
                double endSim = GetSim(geoLine1S[0], geoLine2S[geoLine2S.Length - 1], geoLine1[0], geoLine2[geoLine2.PartCount - 1], false);
                //正向，else反向
                double sim = 0;
                if (firstSim >= endSim)
                {
                    //正向计算相似性
                    sim = GetSim(geoLine1S, geoLine2S, geoLine1, geoLine2, true);
                }
                else
                {
                    //反向计算
                    sim = GetSim(geoLine1S, geoLine2S, geoLine1, geoLine2, false);
                }
                //返回结果
                return sim;
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 获取线对像节点数组
        /// </summary>
        /// <param name="geoLine">线对像</param>
        /// <returns>返回组成该线对像的节点的数组</returns>
        private Point2Ds GetNewPoint2Ds(GeoLine geoLine)
        {
            try
            {
                //获取节点数列,填充起点值
                Point2Ds point2Ds = new Point2Ds();

                point2Ds.Add(new Point2D(geoLine[0][0].X, geoLine[0][0].Y));

                for (int n = 0; n < geoLine.PartCount; n++)
                {
                    for (int m = 1; m < geoLine[n].Count; m++)
                    {
                        point2Ds.Add(new Point2D(geoLine[n][m].X, geoLine[n][m].Y));
                    }

                }
                //返回结果
                return point2Ds;
            }
            catch (Exception)
            {

                throw;
            }
        }
        /// <summary>
        /// 计算距离
        /// </summary>
        /// <param name="x1">要素1的x值</param>
        /// <param name="y1">要素1的y值</param>
        /// <param name="x2">要素2的x值</param>
        /// <param name="y2">要素2的y值</param>
        /// <param name="unit">要素1的坐标单位类型</param>
        /// <returns>返回几何距离，单位m</returns>
        private double GetDistance(double x1, double y1, double x2, double y2, Unit unit)
        {
            try
            {
                //判断单位并计算距离
                switch (unit)
                {
                    case Unit.Meter:
                        return Math.Sqrt(Math.Pow((x1 - x2), 2.0) + Math.Pow((y1 - y2), 2.0));
                    case Unit.Kilometer:
                        return Math.Sqrt(Math.Pow((x1 - x2), 2.0) + Math.Pow((y1 - y2), 2.0)) * 1000;
                    case Unit.Degree:
                        //haversine公式，地球半径取6378.16km
                        double r = 6378.16;
                        double dx = (x2 - x1) * Math.PI / 180;
                        double dy = (y2 - y1) * Math.PI / 180;
                        double uy1 = y1 * Math.PI / 180;
                        double uy2 = y2 * Math.PI / 180;
                        double x = (Math.Sin(dy / 2) * Math.Sin(dy / 2)) + Math.Cos(uy1) * Math.Cos(uy2) * (Math.Sin(dx / 2) * Math.Sin(dx / 2));
                        double xd = (2 * Math.Atan2(Math.Sqrt(x), Math.Sqrt(1 - x))) * r * 1000;
                        return xd;
                    default:
                        return -1;
                        
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
        
    }
}
